package cn.edu.my.regression.nonlinear;

import java.math.BigDecimal;
import java.util.List;
import java.util.ArrayList;

import Jama.Matrix;

import cn.edu.my.regression.model.TradeFundFlowDirection;
import cn.edu.my.regression.nonlinear.NonlinearRegressionDataPoint;
import cn.edu.my.regression.service.TradeFundFlowDirectionService;
import cn.edu.my.regression.service.impl.TradeFundFlowDirectionServiceImpl;

public class ExponentialCurveModel {
	private double totalX;			//x的总和
	private double totalY;			//y的总和
	private double totalXX;			//x的二次方的总和
	private double totalXY;			//x乘y的总和
	private double totalYY;			//y的二次方的总和
	private double averageX;		//x的平均值
	private double averageY;		//y的平均值
	private double standardDeviationX;	//x的标准差
	private double standardDeviationY;	//y的标准差
	private double covarianceXY;		//x与 y的协方差
	private double lineaCorrelationCoefficient;	//直线相关系数
	private double a,b;							//系数
	private double surplusVariance;				//剩余方差
	private double estimatStandardError;		//回归估计标准误差
	private double determinationCoefficient;	//判定系数
	
	private TradeFundFlowDirectionService tradeFundFlowDirectionService;
	private List<TradeFundFlowDirection> tradeFundFlowDirectionList;
	private List<NonlinearRegressionDataPoint> nonlinearRegressionDataPointList;	//坐标点的集合，包括x值和y值
	
	public ExponentialCurveModel() {
	}
	
	// 指数曲线模型
	public void obtainExponentialCurveModel(){
		tradeFundFlowDirectionService=new TradeFundFlowDirectionServiceImpl();
		tradeFundFlowDirectionList = tradeFundFlowDirectionService.readTradeFundFlowDirectionList();
		nonlinearRegressionDataPointList=new ArrayList<NonlinearRegressionDataPoint>();
		for (int i = 0; i < tradeFundFlowDirectionList.size(); i++) {
			NonlinearRegressionDataPoint nonlinearRegressionDataPoint=new NonlinearRegressionDataPoint();
			nonlinearRegressionDataPoint.setX(tradeFundFlowDirectionList.get(i).getSuperLargeSheetNetInflowPercentage());
			nonlinearRegressionDataPoint.setY(tradeFundFlowDirectionList.get(i).getUpDownRange());
			nonlinearRegressionDataPointList.add(nonlinearRegressionDataPoint);
		}
		
		//x的总和
		for (int i = 0; i < nonlinearRegressionDataPointList.size(); i++) {
			totalX += nonlinearRegressionDataPointList.get(i).getX();
		}
		System.out.println("totalX:		" + totalX);
		
		//x的平均值
		averageX = totalX / nonlinearRegressionDataPointList.size();
		System.out.println("averageX:	" + averageX);
		
		//y的总和
		for (int i = 0; i < nonlinearRegressionDataPointList.size(); i++) {
			totalY += nonlinearRegressionDataPointList.get(i).getY();
		}
		System.out.println("totalY:		" + totalY);
		
		//y的平均值
		averageY = totalY / nonlinearRegressionDataPointList.size();
		System.out.println("averageY:	" + averageY);
		
		//x的二次方的总和
		for (int i = 0; i < nonlinearRegressionDataPointList.size(); i++) {
			totalXX += nonlinearRegressionDataPointList.get(i).getX()*nonlinearRegressionDataPointList.get(i).getX();
		}
		System.out.println("totalXX:	" + totalXX);
		
		//x乘y的总和
		for (int i = 0; i < nonlinearRegressionDataPointList.size(); i++) {
			totalXY += nonlinearRegressionDataPointList.get(i).getX()*nonlinearRegressionDataPointList.get(i).getY();
		}
		System.out.println("totalXY:	" + totalXY);
		
		//y的二次方的总和
		for (int i = 0; i < nonlinearRegressionDataPointList.size(); i++) {
			totalYY += nonlinearRegressionDataPointList.get(i).getY()*nonlinearRegressionDataPointList.get(i).getY();
		}
		System.out.println("totalYY:	" + totalYY);
		
		//x的标准差
		double standardDeviationXTemp=0;
		for (int i = 0; i < nonlinearRegressionDataPointList.size(); i++) {
			standardDeviationXTemp+=Math.pow(nonlinearRegressionDataPointList.get(i).getX()-averageX,2);
		}
		standardDeviationX = Math.sqrt(standardDeviationXTemp/nonlinearRegressionDataPointList.size());
		System.out.println("standardDeviationX:	" + standardDeviationX);
		
		//Y的标准差
		double standardDeviationYTemp=0;
		for (int i = 0; i < nonlinearRegressionDataPointList.size(); i++) {
			standardDeviationYTemp+=Math.pow(nonlinearRegressionDataPointList.get(i).getY()-averageY,2);
		}
		standardDeviationY = Math.sqrt(standardDeviationYTemp/nonlinearRegressionDataPointList.size());
		System.out.println("standardDeviationY:	" + standardDeviationY);
		
		//x与 y的协方差
		double covarianceXYTemp=0;
		for (int i = 0; i<nonlinearRegressionDataPointList.size(); i++) {
			covarianceXYTemp+=(nonlinearRegressionDataPointList.get(i).getX()-averageX)*(nonlinearRegressionDataPointList.get(i).getY()-averageY);
		}
		covarianceXY = covarianceXYTemp/nonlinearRegressionDataPointList.size();
		System.out.println("covarianceXY:	" + covarianceXY);
		
		//直线相关系数
		lineaCorrelationCoefficient=covarianceXY/(standardDeviationX*standardDeviationY);
		System.out.println("lineaCorrelationCoefficient:	" + lineaCorrelationCoefficient);
		
		//直线相关系数的取值含义
		if(lineaCorrelationCoefficient>0){
			System.out.println("x与y是正相关");
		}else if(lineaCorrelationCoefficient<0){
			System.out.println("x与y是负相关");
		}else if(Math.abs(lineaCorrelationCoefficient)==1){
			System.out.println("x与y是完全相关");
		}else if(Math.abs(lineaCorrelationCoefficient)!=1){
			System.out.println("x与y是完全不相关");
			return;
		}
		
		//b
		b=lineaCorrelationCoefficient*(standardDeviationY/standardDeviationX);
		System.out.println("b:	" + b);
		
		//a
		a=averageY-b*averageX;
		System.out.println("a:	" + a);
		
		//一元线性回归方程
		System.out.println("一元线性回归方程:   y=" + round(a,2) + "+" + round(b,2) + "x");
		
		//非线性回归方程
		System.out.println("非线性回归方程:   y=" + round(Math.pow(10,a),2) + "*" + round(Math.pow(10,b),2) + "^x");
		
		//剩余方差
		double surplusVarianceTemp=0;
		for(int i=0;i<nonlinearRegressionDataPointList.size();i++){
			surplusVarianceTemp+=Math.pow(nonlinearRegressionDataPointList.get(i).getY()-(b+a*nonlinearRegressionDataPointList.get(i).getX()),2);
		}
		surplusVariance=surplusVarianceTemp/(nonlinearRegressionDataPointList.size()-2);
		System.out.println("surplusVariance:	" + surplusVariance);
		
		//回归估计标准误差
		estimatStandardError=Math.sqrt(surplusVariance);
		System.out.println("estimatStandardError:	" + estimatStandardError);
		
		//判定系数
		determinationCoefficient=1-(Math.pow(estimatStandardError,2)/Math.pow(standardDeviationY,2));
		System.out.println("determinationCoefficient:	" + determinationCoefficient);
	}
	
	private double round(double v, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(Double.toString(v));
		BigDecimal one = new BigDecimal("1");
		return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
}